/*
 * Copyright 2010 - 2011, The PLDesktop Development Team
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#include "virtualpagewithoutpae4k.h"

#include <machine/pc/memory/memmanager.h>
#include <machine/pc/memory/staticmemhandler.h>
#include <machine/pc/memory/virtualpagemanager.h>
#include <machine/machine.h>
#include <kerneldebugconsole.h>

#define VIRTUAL_PAGEDIRECTORY_SIZE 1 * 1024

PLVirtualPageWithoutPAE4k::PLVirtualPageWithoutPAE4k() {
}

void PLVirtualPageWithoutPAE4k::init(PLVirtualPageManager *virtualpagemanager) {
	m_currentPageDirectory = (uint32_t*)PLMachine::instance().kernelMemManger()->memhander()->alloc(VIRTUAL_PAGEDIRECTORY_SIZE * 4);
	for(int i = 0 ; i < VIRTUAL_PAGEDIRECTORY_SIZE ; i++) {
		m_currentPageDirectory[i] = 0;
	}
	virtualpagemanager->setCurrentPageDirectory(m_currentPageDirectory);
}

void *PLVirtualPageWithoutPAE4k::getPhysicalAddress(void *virtualaddr) {
	uint32_t *table;
	uint32_t pdindex = getDirectoryIndex((uint32_t)virtualaddr);
	uint32_t ptindex = getTableIndex((uint32_t)virtualaddr);
	if(m_currentPageDirectory[pdindex] != 0) {
		table = (uint32_t*)(m_currentPageDirectory[pdindex] & 0xfffff000);
		return (void *)(((uint32_t)(table[ptindex]) & ~0xfff) + ((uint32_t)virtualaddr & 4096));
	}
	return 0;
}

void PLVirtualPageWithoutPAE4k::mapPage(void *physaddr, void *virtualaddr, int flagsTable) {
	uint32_t *table;
	uint32_t pdindex = getDirectoryIndex((uint32_t)virtualaddr);
	uint32_t ptindex = getTableIndex((uint32_t)virtualaddr);
	if(m_currentPageDirectory[pdindex] == 0) {
		table = (uint32_t*)PLMachine::instance().kernelMemManger()->memhander()->alloc(VIRTUAL_PAGEDIRECTORY_SIZE * 4);
		for(int i = 0 ; i < VIRTUAL_PAGEDIRECTORY_SIZE ; i++) {
			table[i] = 0;
		}
		m_currentPageDirectory[pdindex] = (((uint32_t)table) & 0xfffff000) | PLVirtualPageManager::PageDirectoryPresent | PLVirtualPageManager::PageDirectoryReadWrite;
//		PLKernelDebugConsole::instance().printf("\n   Set page table: 0x%x with the flags: 0x%x", (((uint32_t)table) & 0xfffff000),
//															 (PLVirtualPageManager::PageDirectoryPresent | PLVirtualPageManager::PageDirectoryReadWrite));
	}
	table = (uint32_t*)(m_currentPageDirectory[pdindex] & 0xfffff000);
	table[ptindex] = (((uint32_t)physaddr) & 0xfffff000) | flagsTable;
}

void PLVirtualPageWithoutPAE4k::setFlags(void *virtualaddr, int flagsTable) {
	uint32_t *table;
	uint32_t pdindex = getDirectoryIndex((uint32_t)virtualaddr);
	uint32_t ptindex = getTableIndex((uint32_t)virtualaddr);
	if(m_currentPageDirectory[pdindex] != 0) {
		table = (uint32_t*)(m_currentPageDirectory[pdindex] & 0xfffff000);
		if(table[ptindex] != 0) {
			uint32_t physaddr = table[ptindex] & 0xfffff000;
			table[ptindex] = physaddr | flagsTable;
		}
	}
}
